<?php

namespace App\Trip\Train\Order\Impl;

use App\Models\Task\SnapTasks\SnapTask;
use App\Models\Train\TrainOrderPassengers\TrainOrderPassenger;
use App\Models\Train\TrainOrders\Repositories\Interfaces\TrainOrdersRepositoryInterface;
use App\Models\Train\TrainOrders\TrainOrder;
use App\Models\Train\TrainOrderTrain\TrainOrderTrain;
use App\Models\Train\TrainSeat\Repositories\Interfaces\TrainSeatRepositoryInterface;
use App\Trip\Code;
use App\Trip\Orders\BookOrders\Train\SelectedSeats\ParseOrderSelectedSeats;
use App\Trip\Train\Order\Interfaces\TrainSnapInterface;
use App\Trip\Train\Providers\PiaoChi\Passenger\CardType;
use App\Trip\Train\Providers\PiaoChi\Passenger\PassengerType;
use App\Trip\Train\Providers\PiaoChi\TrainOrderService;
use Carbon\Carbon;
use Exception;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;

class PiaoChiTrainSnapImpl implements TrainSnapInterface
{

    private TrainOrderService $order_service;
    private TrainOrder        $order;
    private TrainOrderTrain   $main_train;
    private ?SnapTask         $task_info;

    public function __construct(TrainOrder $order)
    {
        $this->setTrainOrder($order);
        $this->setOrderService();
    }

    public function setTrainOrder(TrainOrder $order)
    {
        $this->order     = $order;
        $this->task_info = $order->snap_task_info();
    }

    public function setOrderService()
    {
        $this->order_service = new TrainOrderService();
    }

    /**
     * @throws Exception
     */
    public function snap()
    {
        /**
         * @var TrainOrderTrain     $main_train
         * @var TrainOrderTrain     $origin_main_train
         * @var TrainOrder          $order
         * @var TrainOrderPassenger $passenger
         * @var int                 $type 业务类型:0为出票、1为退票、2为改签、3为打印凭证
         */
        $lock_cache_key = "Train:Order:book:{$this->order->getOrderSn()}";
        if (!Redis::set($lock_cache_key, 1, 'nx', 'ex', config('trip.ttl.minutes'))) {
            throw new Exception("当前不允许执行改签操作,{$this->order->getOrderSn()}");
        }
        $trainOrderRepo = app(TrainOrdersRepositoryInterface::class);
        $trips          = [];
        $order          = $this->order;
        $trips[]        = $this->buildSnapTrip($order);
        Log::info("抢票参数,outs:{$order->getOutOrderSn()}".collect($trips)->toJson(64 | 256));
        try {
            $snap = $this->order_service->trainBook([
                'order_sn' => $order->getOutOrderSn(),
                'trip'     => $trips,
            ]);
        } catch (Exception $e) {
            Log::error("高速抢票订票失败:{$order->getOutOrderSn()},".$e->getMessage());
            throw new Exception("抢票订单订票失败", Code::TRAIN_ORDER_HIGH_SNAP_BOOK_FAILED);
        }
        $res = json_encode($snap, JSON_UNESCAPED_UNICODE);
        Log::info("Train:Order:snap:order_sn:{$order->getOrderSn()},out_order_sn:{$order->getOutOrderSn()},{$res}");
        if ($snap['order_id']) {
            $trainOrderRepo->saveOutOrderId($order, $snap['order_id']);
        }
    }


    /**
     * @throws Exception
     */
    private function buildSnapTrip(TrainOrder $order): array
    {
        // 获取最新状态
        $order->refresh();
        if ($order->isCancel()) {
            throw new Exception("高速抢票订票异常拦截,订单已取消:{$order->getOrderSn()}");
        }

        if (!$this->task_info->isPaidHighLevel()) {
            throw new Exception("高速抢票订票异常拦截,任务非高速付费抢票:{$order->getOrderSn()}");
        }


        /**
         * @var TrainOrderPassenger $passenger
         */
        // 主行程
        $date             = $order->getTrainDate();
        $this->main_train = $main_train = $order->getMainTrain();
        $from_station     = $main_train->getFromName();
        $to_station       = $main_train->getToName();
        $train_code       = $main_train->getTrainCode();
        $passengers       = $order->getPassengers();
        $selected_seats   = $this->order->getSelectedSeats();

        // 目前info 信息主要填写选座信息
        $info = "";
        if ($selected_seats) {
            $selectSeat = new ParseOrderSelectedSeats($selected_seats);
            $info       = $selectSeat->getSelectedSeatRemark();
        }
        // 备选行程
        $carcode_time_mutil_date = $this->buildAlternativeTrips();
        $trip_passengers         = [];
        foreach ($passengers as $key => $passenger) {
            $trip_passengers[$key] = [
                "realname"         => $passenger->getTrueName(),
                "realcode"         => $passenger->getIdentityCode(),
                "realcode_guoji"   => "中华人民共和国",
                "cardtype"         => CardType::getCardType($passenger->getIdentityType()),
                "peopletype"       => PassengerType::getPeopleType($passenger->getPassengerType()),
                "seattip"          => $passenger->getSeatName(),
                "mobile"           => $passenger->getMobile(),
                "price"            => $passenger->getSeatPrice(),
                "paytype"          => $this->order_service::PAY_TYPE_ELECTRONIC,
                "info"             => $info,
                "type"             => $this->order_service::BOOK_TYPE_SNAP,
                "sub_passenger_id" => $passenger->subPassengerId(),
            ];
        }
        return [
            "type"                    => $this->order_service::BUSINESS_TYPE_TICKET,
            "flytime"                 => $date,
            "fromcity"                => $from_station,
            "tocity"                  => $to_station,
            "carcode"                 => $train_code,
            "info"                    => $info,
            "carcode_time_mutil_date" => $carcode_time_mutil_date,
            "passenger"               => $trip_passengers,
            //            "qiang_passenger_list"    => $trip_passengers,
            "sub_trip_id"             => $order->getOrderSn(),            // 回调用于判别是哪笔订单
            "stop_time"               => $this->task_info->getStopTime(), // 抢票停止时间
        ];
    }

    /**
     * 构造备选行程
     *
     * @return array
     */
    private function buildAlternativeTrips(): array
    {
        $trains = $this->order->getAlternativeTrains();
        $dates  = $this->order->getAlternativeTrainDates();
        $seats  = $this->order->getAlternativeSeats();

        // 排序 优先主行程的
        $trainSeatRepo = app(TrainSeatRepositoryInterface::class);
        // 当前日期 , 当前坐席  当前车次
        $sub_trip_id = $this->order->getOrderSn();
        $multiples   = [];
        // 最多限定20组数据 优先默认车次,日期,及座位 ,如果哦数量少则 优先下一组日期
        $max_group = 20;
        foreach ($trains as $train_key => $train) {
            $train_code = $train['train_code'];
            $from_name  = $train['from_name'];
            $from_code  = $train['from_code'];
            $to_name    = $train['to_name'];
            $to_code    = $train['to_code'];
            $start_time = $train['start_time'];

            foreach ($dates as $date_key => $date) {
                foreach ($seats as $seat_key => $seat) {
                    if (count($multiples) >= $max_group) {
                        break;
                    }
                    $depart_at = Carbon::parse("{$date} {$start_time}")->format("Y-m-d H:i");
                    if ($train_code == $this->main_train->getTrainCode()
                        && $from_code == $this->main_train->getFromStationCode()
                        && $to_code == $this->main_train->getToStationCode()
                        && $seat == $this->order->getSeatName()
                        && $depart_at == Carbon::parse($this->main_train->getStartAt())->format("Y-m-d H:i")
                    ) {
                        continue;
                    }
                    $train_seat = $trainSeatRepo->findByTrainCodeAndSeatName($train_code, $from_code, $to_code, $seat);
                    if (!$train_seat) {
                        continue;
                    }
                    $multiples[] = [
                        "sub_trip_id" => $sub_trip_id,
                        "fromcity"    => $from_name,
                        "tocity"      => $to_name,
                        "flytime"     => $depart_at,
                        "carcode"     => $train_code,
                        "seattip"     => $seat,
                        "price"       => $train_seat->getSeatPrice(),
                        "info"        => "",
                    ];
                }
            }
        }

        return $multiples;
    }
}